﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Transactions;

namespace Unimaq.Macroprocesos.LogicaNegocio
{
    public class ProcesoBLL
    {
        public List<AccesoDatos.Proceso> Listar()
        {
            AccesoDatos.ProcesoDAO procesoDAO = new AccesoDatos.ProcesoDAO();
            return procesoDAO.Listar();
        }

        public List<AccesoDatos.Proceso> Listar(AccesoDatos.Empresa selectedEmpresa)
        {
            List<AccesoDatos.Proceso> lista = Listar();
            return lista.Where(x => x.IdEmpresa == selectedEmpresa.Id && x.IdPadreProceso.HasValue == false).ToList();
        }

        public List<AccesoDatos.Proceso> Listar(AccesoDatos.Proceso selectedProceso)
        {
            List<AccesoDatos.Proceso> lista = Listar();
            return lista.Where(x => (x.IdEmpresa.HasValue ? x.IdEmpresa.Value : -1).Equals(selectedProceso.IdEmpresa) && (x.IdPadreProceso.HasValue ? x.IdPadreProceso.Value : -1) == selectedProceso.Id).ToList();
        }

        public List<AccesoDatos.Proceso> ListarxEmpresa(AccesoDatos.Empresa selectedEmpresa)
        {
            List<AccesoDatos.Proceso> lista = Listar();
            return lista.Where(x => x.IdEmpresa == selectedEmpresa.Id).ToList();
        }

        public int Registrar(AccesoDatos.Proceso nuevoProceso)
        {
            AccesoDatos.ProcesoDAO procesoDAO = new AccesoDatos.ProcesoDAO();
            return procesoDAO.Registrar(nuevoProceso);
        }

        public AccesoDatos.Proceso GetProceso(AccesoDatos.Proceso selectedProceso)
        {
            List<AccesoDatos.Proceso> lista = Listar();
            return lista.SingleOrDefault(x => x.Id.Equals(selectedProceso.Id));
        }

        public List<AccesoDatos.Proceso> Buscar(int idEmpresa, string codigoProceso)
        {
            List<AccesoDatos.Proceso> lista = Listar();
            return lista.Where(x => (x.IdEmpresa.HasValue ? x.IdEmpresa.Value : 0).Equals(idEmpresa) && x.CodigoProceso.Equals(codigoProceso, StringComparison.CurrentCultureIgnoreCase)).ToList();
        }

        public List<AccesoDatos.Proceso> Buscar(AccesoDatos.Empresa selectedEmpresa, string atributo, string valor)
        {
            List<AccesoDatos.Proceso> lista = ListarxEmpresa(selectedEmpresa);
            List<AccesoDatos.Proceso> result = new List<AccesoDatos.Proceso>();

            if (!string.IsNullOrWhiteSpace(valor))
            {
                switch (atributo)
                {
                    case "codigo":
                        result = lista.Where(x => x.CodigoProceso.Contains(valor)).ToList();
                        break;
                    case "nombre":
                        result = lista.Where(x => x.Nombre.Contains(valor)).ToList();
                        break;
                }
            }
            else 
            {
                result = lista;
            }

            return result;
        }

        public int Actualizar(AccesoDatos.Proceso selectedProceso, AccesoDatos.Proceso updProceso, bool updCodigo)
        {
            int resultado = 0; 
            AccesoDatos.ProcesoDAO procesoDAO = new AccesoDatos.ProcesoDAO();

            if (updCodigo)
            {
                //Actualizacion del código del proceso
                Unimaq.Macroprocesos.AccesoDatos.Proceso procPadre = this.GetProcesoPadre(updProceso);

                string prefCodPadre = procPadre.CodigoProceso;
                string endCodProceso = updProceso.CodigoProceso.Substring(updProceso.CodigoProceso.LastIndexOf('-') + 1);

                updProceso.CodigoProceso = string.Format("{0}-{1}", prefCodPadre, endCodProceso);

                resultado = procesoDAO.Actualizar(selectedProceso, updProceso);
            }
            else
            {
                resultado = procesoDAO.Actualizar(selectedProceso, updProceso);
            }

            return resultado;
        }

        public AccesoDatos.Proceso GetProcesoPadre(AccesoDatos.Proceso selectedProceso)
        {
            List<AccesoDatos.Proceso> lista = Listar();
            return lista.SingleOrDefault(x => x.Id.Equals((selectedProceso.IdPadreProceso.HasValue ? selectedProceso.IdPadreProceso.Value : -1)));
        }

        public AccesoDatos.Proceso GetProceso(AccesoDatos.Documento selectedDocumento)
        {
            List<AccesoDatos.Proceso> lista = Listar();
            return lista.SingleOrDefault(x => x.Id.Equals((selectedDocumento.IdProceso.HasValue ? selectedDocumento.IdProceso.Value : -1))); 
        }

        public int Eliminar(AccesoDatos.Proceso selectedProceso)
        {
            AccesoDatos.ProcesoDAO procesoDAO = new AccesoDatos.ProcesoDAO();
            return procesoDAO.Eliminar(selectedProceso);
        }

        public void EliminarProceso(AccesoDatos.Proceso selectedProceso, ref int result , bool continuar)
        {
            if (continuar)
            {
                AccesoDatos.ProcesoDAO procesoDAO = new AccesoDatos.ProcesoDAO();
                LogicaNegocio.DocumentoBLL documentoBLL = new DocumentoBLL();

                List<AccesoDatos.Documento> listaDocumento = documentoBLL.Listar(selectedProceso);
                List<AccesoDatos.Proceso> listaProceso = Listar(selectedProceso);

                //eliminamos sus documentos
                if (listaDocumento.Count > 0)
                {
                    foreach (AccesoDatos.Documento doc in listaDocumento)
                    {
                        int valResult1 = documentoBLL.Eliminar(doc);

                        if (valResult1 > 0)
                        {
                            result += valResult1;
                        }
                        else
                        {
                            continuar = false;
                            break;
                        }
                    }
                }

                //recursividad de sus procesos
                if (continuar)
                {
                    if (listaProceso.Count > 0)
                    {
                        foreach (AccesoDatos.Proceso proc in listaProceso)
                        {
                            EliminarProceso(proc, ref result, continuar);
                        }

                        //Si es correcto 
                        if (continuar)
                        {
                            //Entonces eliminamos este proceso
                            int valResult2 = Eliminar(selectedProceso);

                            if (valResult2 > 0)
                            {
                                result += valResult2;
                            }
                            else
                            {
                                continuar = false;
                            }
                        }
                    }
                    else //no tiene procesos, se elimina
                    {
                        int valResult3 = Eliminar(selectedProceso);

                        if (valResult3 > 0)
                        {
                            result += valResult3;
                        }
                        else
                        {
                            continuar = false;
                        }
                    } 
                }
            }
        }

        public void ActualizarProcesosHijos(AccesoDatos.Proceso selectedProceso, ref int result)
        {
            Unimaq.Macroprocesos.AccesoDatos.Proceso sProceso = new AccesoDatos.Proceso()
            {
                Id = selectedProceso.Id,
                IdPadreProceso = selectedProceso.IdPadreProceso,
                IdEmpresa = selectedProceso.IdEmpresa
            };

            int resultado = Actualizar(sProceso, selectedProceso, true);

            if (resultado > 0)
            {
                result += resultado;
                List<Unimaq.Macroprocesos.AccesoDatos.Proceso> lista = this.Listar(selectedProceso);

                if (lista.Count > 0)
                {
                    foreach (AccesoDatos.Proceso pr in lista)
                    {
                        ActualizarProcesosHijos(pr, ref result);
                    }
                }
            }                        

            //if (lista.Count > 0)
            //{
            //    foreach (AccesoDatos.Proceso proc in lista)
            //    {
            //        ActualizarProcesosHijos(proc, ref result);
            //    }
            //}
            //else
            //{
            //    Unimaq.Macroprocesos.AccesoDatos.Proceso procPadre = this.GetProcesoPadre(selectedProceso);

            //    if (procPadre != null)
            //    {
            //        selectedProceso.IdEmpresa = procPadre.IdEmpresa;

            //        Unimaq.Macroprocesos.AccesoDatos.Proceso sProc =
            //            new AccesoDatos.Proceso()
            //            {
            //                Id = selectedProceso.Id,
            //            };

            //        result += this.Actualizar(sProc, selectedProceso, true); 
            //    }
            //}
        }

        public int ActualizarCodigosProceso(AccesoDatos.TipoProceso updTipoProceso)
        {
            int result = 0;
            List<AccesoDatos.Proceso> lista = this.Listar();

            foreach (AccesoDatos.Proceso p in lista)
            {
                string subCode = p.CodigoProceso.Substring(p.CodigoProceso.IndexOf('-') + 1).Trim();
                p.CodigoProceso = string.Format("{0}-{1}", updTipoProceso.Codigo.Trim(), subCode);
                result += this.Actualizar(new AccesoDatos.Proceso() { Id = p.Id }, p, false);

                if (result == 0)
                {
                    result = 0;
                    break;
                }
            }

            return result;
        }
    }
}
